<?php declare(strict_types=1);
/**
 * @author      xianganyall <xianganyall@gmail.com>
 * @copyright   2023-2025 owner
 **/

namespace Srv\Libs\Tools;

use Exception;
use Srv\Libs\Common\CommString;
use Srv\Libs\Common\CommValid;
use Srv\Libs\Frame\Conf;

final class IpAddr
{
    private static ?self $Instance      = null;             // 实例对象
    private $fp                         = null;             // 打开的资源文件句柄
    private int $firstIp                = 0;                // IP开始地址
    private int $lastIp                 = 0;                // IP最后地址
    private int $totalIp                = 0;                // 总IP数
    public const IP_DAT_DEFAULT_KEY     = 'IP.datPath';     // 默认资源文件配置Key
    public const NAME_CHINA             = '中国';
    public const NAME_PROVINCE          = '省';
    public const NAME_CITY              = '市';
    public const NAME_XIAN              = '县';
    public const NAME_QU                = '区';
    private array $ispList              = [                 // 运营商定义
        ['联通',   '联通'],
        ['移动',   '移动'],
        ['铁通',   '铁通'],
        ['长城',   '长城'],
        ['鹏博士',  '鹏博士'],
        ['电信',   '电信'],
        ['大学',   '教育网'],
        ['学院',   '教育网'],
        ['教育',   '教育网'],
    ];
    private array $provinceList         = [                 // 省份定义[0-省,1-直辖市,2-自治区,3-特别行政区]
        ['110000', 1, '北京',   '北京市'],
        ['120000', 1, '天津',   '天津市'],
        ['500000', 1, '重庆',   '重庆市'],
        ['310000', 1, '上海',   '上海市'],
        ['230000', 0, '黑龙江', '黑龙江省'],
        ['130000', 0, '河北',   '河北省'],
        ['140000', 0, '山西',   '山西省'],
        ['210000', 0, '辽宁',   '辽宁省'],
        ['220000', 0, '吉林',   '吉林省'],
        ['320000', 0, '江苏',   '江苏省'],
        ['330000', 0, '浙江',   '浙江省'],
        ['340000', 0, '安徽',   '安徽省'],
        ['350000', 0, '福建',   '福建省'],
        ['360000', 0, '江西',   '江西省'],
        ['370000', 0, '山东',   '山东省'],
        ['410000', 0, '河南',   '河南省'],
        ['420000', 0, '湖北',   '湖北省'],
        ['430000', 0, '湖南',   '湖南省'],
        ['440000', 0, '广东',   '广东省'],
        ['460000', 0, '海南',   '海南省'],
        ['510000', 0, '四川',   '四川省'],
        ['520000', 0, '贵州',   '贵州省'],
        ['530000', 0, '云南',   '云南省'],
        ['610000', 0, '陕西',   '陕西省'],
        ['620000', 0, '甘肃',   '甘肃省'],
        ['630000', 0, '青海',   '青海省'],
        ['710000', 0, '台湾',   '台湾省'],
        ['150000', 2, '内蒙古', '内蒙古自治区'],
        ['450000', 2, '广西',   '广西壮族自治区'],
        ['640000', 2, '宁夏',   '宁夏回族自治区'],
        ['650000', 2, '新疆',   '新疆维吾尔自治区'],
        ['540000', 2, '西藏',   '西藏自治区'],
        ['810000', 3, '香港',   '香港'],
        ['820000', 3, '澳门',   '澳门'],
    ];
    private array $countryList          = [                 // 国家定义
        [4,   '阿富汗'],
        [8,   '阿尔巴尼亚'],
        [10,  '南极洲'],
        [12,  '阿尔及利亚'],
        [16,  '美属萨摩亚'],
        [20,  '安道尔'],
        [24,  '安哥拉'],
        [28,  '安提瓜和巴布达'],
        [31,  '阿塞拜疆'],
        [32,  '阿根廷'],
        [36,  '澳大利亚'],
        [40,  '奥地利'],
        [44,  '巴哈马'],
        [48,  '巴林'],
        [50,  '孟加拉国'],
        [51,  '亚美尼亚'],
        [52,  '巴巴多斯'],
        [56,  '比利时'],
        [60,  '百慕大'],
        [64,  '不丹'],
        [68,  '玻利维亚'],
        [70,  '波黑'],
        [72,  '博茨瓦纳'],
        [74,  '布韦岛'],
        [76,  '巴西'],
        [84,  '伯利兹'],
        [86,  '英属印度洋领地'],
        [90,  '所罗门群岛'],
        [92,  '英属维尔京群岛'],
        [96,  '文莱'],
        [100, '保加利亚'],
        [104, '缅甸'],
        [108, '布隆迪'],
        [112, '白俄罗斯'],
        [116, '柬埔寨'],
        [120, '喀麦隆'],
        [124, '加拿大'],
        [132, '佛得角'],
        [136, '开曼群岛'],
        [140, '中非'],
        [144, '斯里兰卡'],
        [148, '乍得'],
        [152, '智利'],
        [156, '中国'],
        [162, '圣诞岛'],
        [166, '科科斯（基林）群岛'],
        [170, '哥伦比亚'],
        [174, '科摩罗'],
        [175, '马约特'],
        [178, '刚果共和国'],
        [180, '刚果民主共和国'],
        [184, '库克群岛'],
        [188, '哥斯达黎加'],
        [191, '克罗地亚'],
        [192, '古巴'],
        [196, '塞浦路斯'],
        [203, '捷克'],
        [204, '贝宁'],
        [208, '丹麦'],
        [212, '多米尼克'],
        [214, '多米尼加'],
        [218, '厄瓜多尔'],
        [222, '萨尔瓦多'],
        [226, '赤道几内亚'],
        [231, '埃塞俄比亚'],
        [232, '厄立特里亚'],
        [233, '爱沙尼亚'],
        [234, '法罗群岛'],
        [238, '福克兰群岛'],
        [239, '南乔治亚和南桑威奇群岛'],
        [242, '斐济'],
        [246, '芬兰'],
        [248, '奥兰'],
        [250, '法国'],
        [254, '法属圭亚那'],
        [258, '法属波利尼西亚'],
        [260, '法属南部和南极领地'],
        [262, '吉布提'],
        [266, '加蓬'],
        [268, '格鲁吉亚'],
        [270, '冈比亚'],
        [275, '巴勒斯坦'],
        [276, '德国'],
        [288, '加纳'],
        [292, '直布罗陀'],
        [296, '基里巴斯'],
        [300, '希腊'],
        [304, '格陵兰'],
        [308, '格林纳达'],
        [312, '瓜德罗普'],
        [316, '关岛'],
        [320, '危地马拉'],
        [324, '几内亚'],
        [328, '圭亚那'],
        [332, '海地'],
        [334, '赫德岛和麦克唐纳群岛'],
        [336, '梵蒂冈'],
        [340, '洪都拉斯'],
        [348, '匈牙利'],
        [352, '冰岛'],
        [356, '印度'],
        [360, '印尼'],
        [364, '伊朗'],
        [368, '伊拉克'],
        [372, '爱尔兰'],
        [376, '以色列'],
        [380, '意大利'],
        [384, '科特迪瓦'],
        [388, '牙买加'],
        [392, '日本'],
        [398, '哈萨克斯坦'],
        [400, '约旦'],
        [404, '肯尼亚'],
        [408, '朝鲜'],
        [410, '韩国'],
        [414, '科威特'],
        [417, '吉尔吉斯斯坦'],
        [418, '老挝'],
        [422, '黎巴嫩'],
        [426, '莱索托'],
        [428, '拉脱维亚'],
        [430, '利比里亚'],
        [434, '利比亚'],
        [438, '列支敦士登'],
        [440, '立陶宛'],
        [442, '卢森堡'],
        [450, '马达加斯加'],
        [454, '马拉维'],
        [458, '马来西亚'],
        [462, '马尔代夫'],
        [466, '马里'],
        [470, '马耳他'],
        [474, '马提尼克'],
        [478, '毛里塔尼亚'],
        [480, '毛里求斯'],
        [484, '墨西哥'],
        [492, '摩纳哥'],
        [496, '蒙古'],
        [498, '摩尔多瓦'],
        [499, '黑山'],
        [500, '蒙特塞拉特'],
        [504, '摩洛哥'],
        [508, '莫桑比克'],
        [512, '阿曼'],
        [516, '纳米比亚'],
        [520, '瑙鲁'],
        [524, '尼泊尔'],
        [528, '荷兰'],
        [531, '库拉索'],
        [533, '阿鲁巴'],
        [534, '荷属圣马丁'],
        [535, '荷兰加勒比区'],
        [540, '新喀里多尼亚'],
        [548, '瓦努阿图'],
        [554, '新西兰'],
        [558, '尼加拉瓜'],
        [562, '尼日尔'],
        [566, '尼日利亚'],
        [570, '纽埃'],
        [574, '诺福克岛'],
        [578, '挪威'],
        [580, '北马里亚纳群岛'],
        [581, '美国本土外小岛屿'],
        [583, '密克罗尼西亚联邦'],
        [584, '马绍尔群岛'],
        [585, '帕劳'],
        [586, '巴基斯坦'],
        [591, '巴拿马'],
        [598, '巴布亚新几内亚'],
        [600, '巴拉圭'],
        [604, '秘鲁'],
        [608, '菲律宾'],
        [612, '皮特凯恩群岛'],
        [616, '波兰'],
        [620, '葡萄牙'],
        [624, '几内亚比绍'],
        [626, '东帝汶'],
        [630, '波多黎各'],
        [634, '卡塔尔'],
        [638, '留尼汪'],
        [642, '罗马尼亚'],
        [643, '俄罗斯'],
        [646, '卢旺达'],
        [652, '圣巴泰勒米'],
        [654, '圣赫勒拿、阿森松和特里斯坦-达库尼亚'],
        [659, '圣基茨和尼维斯'],
        [660, '安圭拉'],
        [662, '圣卢西亚'],
        [663, '法属圣马丁'],
        [666, '圣皮埃尔和密克隆'],
        [670, '圣文森特和格林纳丁斯'],
        [674, '圣马力诺'],
        [678, '圣多美和普林西比'],
        [682, '沙特阿拉伯'],
        [686, '塞内加尔'],
        [688, '塞尔维亚'],
        [690, '塞舌尔'],
        [694, '塞拉利昂'],
        [702, '新加坡'],
        [703, '斯洛伐克'],
        [704, '越南'],
        [705, '斯洛文尼亚'],
        [706, '索马里'],
        [710, '南非'],
        [716, '津巴布韦'],
        [724, '西班牙'],
        [728, '南苏丹'],
        [729, '苏丹'],
        [732, '西撒哈拉'],
        [740, '苏里南'],
        [744, '斯瓦尔巴和扬马延'],
        [748, '斯威士兰'],
        [752, '瑞典'],
        [756, '瑞士'],
        [760, '叙利亚'],
        [762, '塔吉克斯坦'],
        [764, '泰国'],
        [768, '多哥'],
        [772, '托克劳'],
        [776, '汤加'],
        [780, '特立尼达和多巴哥'],
        [784, '阿联酋'],
        [788, '突尼斯'],
        [792, '土耳其'],
        [795, '土库曼斯坦'],
        [796, '特克斯和凯科斯群岛'],
        [798, '图瓦卢'],
        [800, '乌干达'],
        [804, '乌克兰'],
        [807, '北马其顿'],
        [818, '埃及'],
        [826, '英国'],
        [831, '根西'],
        [832, '泽西'],
        [833, '马恩岛'],
        [834, '坦桑尼亚'],
        [840, '美国'],
        [850, '美属维尔京群岛'],
        [854, '布基纳法索'],
        [858, '乌拉圭'],
        [860, '乌兹别克斯坦'],
        [862, '委内瑞拉'],
        [876, '瓦利斯和富图纳'],
        [882, '萨摩亚'],
        [887, '也门'],
        [894, '赞比亚'],
    ];
    private array $countryIndexList     = [     // 强制定义国家数字代码
        '中国' => 156,
        '阿尔巴尼亚' => 8,
        '阿尔及利亚' => 12,
        '阿富汗' => 4,
        '阿根廷' => 32,
        '阿联酋' => 784,
        '阿鲁巴' => 533,
        '阿曼' => 512,
        '阿塞拜疆' => 31,
        '埃及' => 818,
        '埃塞俄比亚' => 231,
        '爱尔兰' => 372,
        '爱沙尼亚' => 233,
        '安哥拉' => 20,
        '安圭拉' => 24,
        '安提瓜和巴布达' => 660,
        '奥地利' => 28,
        '奥兰群岛' => 248,
        '澳大利亚' => 36,
        '巴巴多斯' => 52,
        '巴布亚新几内亚' => 598,
        '巴哈马' => 44,
        '巴基斯坦' => 586,
        '巴拉圭' => 600,
        '巴勒斯坦' => 275,
        '巴林' => 48,
        '巴拿马' => 591,
        '巴西' => 76,
        '白俄罗斯' => 112,
        '百慕大' => 60,
        '保加利亚' => 100,
        '北马里亚纳群岛' => 580,
        '贝宁' => 204,
        '比利时' => 56,
        '冰岛' => 352,
        '波多黎各' => 630,
        '波黑' => 70,
        '波兰' => 616,
        '玻利维亚' => 68,
        '伯利兹' => 84,
        '博茨瓦纳' => 72,
        '不丹' => 64,
        '布基纳法索' => 854,
        '布隆迪' => 108,
        '赤道几内亚' => 226,
        '丹麦' => 208,
        '德国' => 276,
        '东帝汶' => 626,
        '多哥' => 768,
        '多米尼加' => 214,
        '多米尼克' => 212,
        '俄罗斯' => 643,
        '厄瓜多尔' => 218,
        '厄立特里亚' => 232,
        '法国' => 250,
        '法罗群岛' => 234,
        '法属波利尼西亚' => 258,
        '法属圭亚那' => 254,
        '法属圣马丁' => 663,
        '梵蒂冈' => 336,
        '菲律宾' => 608,
        '斐济' => 242,
        '芬兰' => 246,
        '佛得角' => 132,
        '冈比亚' => 270,
        '刚果共和国' => 178,
        '哥伦比亚' => 170,
        '哥斯达黎加' => 188,
        '格林纳达' => 308,
        '格陵兰' => 304,
        '格鲁吉亚' => 268,
        '根西岛' => 831,
        '古巴' => 192,
        '瓜德罗普' => 312,
        '关岛' => 316,
        '圭亚那' => 328,
        '哈萨克斯坦' => 398,
        '海地' => 332,
        '韩国' => 410,
        '荷兰' => 528,
        '黑山' => 499,
        '洪都拉斯' => 340,
        '基里巴斯' => 296,
        '吉布提' => 262,
        '吉尔吉斯斯坦' => 417,
        '几内亚' => 324,
        '几内亚比绍' => 624,
        '加拿大' => 124,
        '加纳' => 288,
        '加蓬' => 266,
        '柬埔寨' => 116,
        '捷克' => 203,
        '津巴布韦' => 716,
        '喀麦隆' => 120,
        '卡塔尔' => 634,
        '开曼群岛' => 136,
        '科摩罗' => 174,
        '科特迪瓦' => 384,
        '科威特' => 414,
        '克罗地亚' => 191,
        '肯尼亚' => 404,
        '库克群岛' => 184,
        '拉脱维亚' => 428,
        '莱索托' => 426,
        '老挝' => 418,
        '黎巴嫩' => 422,
        '利比里亚' => 430,
        '利比亚' => 434,
        '立陶宛' => 440,
        '列支敦士登' => 438,
        '留尼汪' => 638,
        '卢森堡' => 442,
        '卢旺达' => 646,
        '罗马尼亚' => 642,
        '马达加斯加' => 450,
        '马恩岛' => 833,
        '马尔代夫' => 462,
        '马耳他' => 470,
        '马拉维' => 454,
        '马来西亚' => 458,
        '马里' => 466,
        '马绍尔群岛' => 584,
        '马提尼克' => 474,
        '毛里求斯' => 480,
        '毛里塔尼亚' => 478,
        '美国' => 840,
        '美属萨摩亚' => 16,
        '美属维尔京群岛' => 850,
        '蒙古' => 496,
        '蒙塞拉特岛' => 500,
        '孟加拉' => 50,
        '密克罗尼西亚联邦' => 583,
        '秘鲁' => 604,
        '缅甸' => 104,
        '摩尔多瓦' => 498,
        '摩洛哥' => 504,
        '摩纳哥' => 492,
        '墨西哥' => 484,
        '莫桑比克' => 508,
        '纳米比亚' => 516,
        '南非' => 710,
        '瑙鲁' => 520,
        '尼泊尔' => 524,
        '尼加拉瓜' => 558,
        '尼日尔' => 562,
        '尼日利亚' => 566,
        '纽埃' => 570,
        '挪威' => 578,
        '诺福克岛' => 574,
        '帕劳' => 585,
        '葡萄牙' => 620,
        '日本' => 392,
        '瑞典' => 752,
        '瑞士' => 756,
        '萨尔瓦多' => 222,
        '萨摩亚' => 882,
        '塞尔维亚' => 688,
        '塞拉利昂' => 694,
        '塞内加尔' => 686,
        '塞浦路斯' => 196,
        '塞舌尔' => 690,
        '沙特阿拉伯' => 682,
        '圣多美和普林西比' => 678,
        '圣基茨和尼维斯' => 659,
        '圣卢西亚' => 662,
        '圣马力诺' => 674,
        '圣皮埃尔和密克隆' => 666,
        '圣文森特和格林纳丁斯' => 670,
        '斯里兰卡' => 144,
        '斯洛伐克' => 703,
        '斯洛文尼亚' => 705,
        '斯威士兰' => 748,
        '苏丹' => 729,
        '苏里南' => 740,
        '所罗门群岛' => 90,
        '索马里' => 706,
        '塔吉克斯坦' => 762,
        '泰国' => 764,
        '坦桑尼亚' => 834,
        '汤加' => 776,
        '特克斯和凯科斯群岛' => 796,
        '特立尼达和多巴哥' => 780,
        '突尼斯' => 788,
        '图瓦卢' => 798,
        '土耳其' => 792,
        '土库曼斯坦' => 795,
        '托克劳' => 772,
        '瓦利斯和富图纳' => 876,
        '瓦努阿图' => 548,
        '危地马拉' => 320,
        '委内瑞拉' => 862,
        '文莱' => 96,
        '乌兹别克斯坦' => 860,
        '乌干达' => 800,
        '乌克兰' => 804,
        '乌拉圭' => 858,
        '希腊' => 300,
        '西班牙' => 724,
        '西撒哈拉' => 732,
        '新加坡' => 702,
        '新喀里多尼亚' => 540,
        '新西兰' => 554,
        '匈牙利' => 348,
        '叙利亚' => 760,
        '牙买加' => 388,
        '亚美尼亚' => 51,
        '也门' => 887,
        '伊拉克' => 368,
        '伊朗' => 364,
        '以色列' => 376,
        '意大利' => 380,
        '印度' => 356,
        '印度尼西亚' => 360,
        '英国' => 826,
        '英属维尔京群岛' => 92,
        '英属印度洋领地' => 86,
        '约旦' => 400,
        '越南' => 704,
        '赞比亚' => 894,
        '泽西岛' => 832,
        '乍得' => 148,
        '朝鲜' => 408,
        '直布罗陀' => 292,
        '智利' => 152,
        '中非' => 140,
        '刚果(布)' => 180,
        '刚果(金)' => 180,
        '北美地区' => 0,
        '亚太地区' => 0,
        '拉美地区' => 0,
        '非洲地区' => 0,
        '非洲' => 0,
        '欧洲和中东地区' => 0,
        '欧洲' => 0,
        '波斯尼亚和黑塞哥维那' => 0,
        '荷属安的列斯' => 0,
        '凯里' => 0,
        '马其顿' => 0,
        '维多利亚' => 0,
    ];

    /**
     * @param string $fileUrl
     * @throws Exception
     * __construct
     */
    public function __construct(string $fileUrl = '')
    {
        if(strlen($fileUrl) < 1) $fileUrl = Conf::getString(self::IP_DAT_DEFAULT_KEY, false);
        if(($this->fp = @fopen($fileUrl, 'rb')) !== false){
            $this->firstIp    = $this->getLong();
            $this->lastIp     = $this->getLong();
            $this->totalIp    = intval(($this->lastIp - $this->firstIp)/7);
        }else{
            throw new Exception('Conf IpDat File Error');
        }
    }

    /**
     * __destruct
     */
    public function __destruct()
    {
        if($this->fp) @fclose($this->fp);
        $this->fp = null;
    }

    /**
     * @return static
     * instance
     */
    private static function instance():self
    {
        if(self::$Instance instanceof self) return self::$Instance;
        self::$Instance         = new self();
        return self::$Instance;
    }

    /**
     * @param string $ipStr
     * @return array
     * getLocationAnalyze
     */
    public static function getLocationAnalyze(string $ipStr):array
    {
        $Instance               = self::instance();
        $location               = $Instance->getLocation($ipStr);
        $location['analyze']    = $Instance->analyze($location['country'], $location['area']);
        return $location;
    }

    /**
     * @param string $address
     * @return array
     * getAddressAnalyze
     */
    public static function getAddressAnalyze(string $address):array
    {
        return self::instance()->analyze($address, '');
    }

    /**
     * @param string $ipStr
     * @return array
     * getLocationInfo
     */
    public static function getLocationInfo(string $ipStr):array
    {
        return self::instance()->getLocation($ipStr);
    }

    /**
     * @return int
     * 解析Long
     */
    private function getLong():int
    {
        $result = unpack('Vlong', @fread($this->fp, 4));
        return intval($result['long']??0);
    }
    
    /**
     * @return int
     * 解析Long3
     */
    private function getLong3():int
    {
        $result = unpack('Vlong', @fread($this->fp, 3).chr(0));
        return intval($result['long']??0);
    }

    /**
     * @return string
     * 获取地区值
     */
    private function getArea():string
    {
        $byte   = @fread($this->fp, 1);
        if($byte === false || !is_string($byte)) return '';
        switch(ord($byte)){
            case 0:{
                return '';
            }
            case 1:
            case 2:{
                fseek($this->fp, $this->getLong3());
                return $this->getString();
            }
            default:{
                return $this->getString($byte);
            }
        }
    }

    /**
     * @param string $ip
     * @return string
     * 解析IP
     */
    private function packIp(string $ip):string
    {
        return pack('N', intval(ip2long($ip)));
    }
    
    /**
     * @param string $data
     * @return string
     * 获取字符串
     */
    private function getString(string $data = ''):string
    {
        $char   = @fread($this->fp, 1);
        if($char === false || !is_string($char)) return '';
        while(ord($char) > 0){
            $data .= $char;
            $char = fread($this->fp, 1);
        }
        return trim($data);
    }
    
    /**
     * @param string $ipStr
     * @return array
     * 获取Location值
     */
    private function getLocation(string $ipStr):array
    {
        $location       = ['ipStr' => '', 'startIp' => '', 'endIp' => '', 'country' => '', 'area' => ''];
        if(!$this->fp || $this->totalIp < 1 || mb_strlen($ipStr) < 7 || !CommValid::isIp($ipStr)) return $location;
        $location['ipStr'] = $ipStr;
        $ip             = $this->packIp($location['ipStr']);
        $l              = 0;
        $u              = $this->totalIp;
        $findIp         = $this->lastIp;
        while($l <= $u){
            $i              = floor(($l+$u)/2);
            fseek($this->fp, intval($this->firstIp+$i*7));
            $startIp        = strrev(fread($this->fp, 4));
            if($ip < $startIp){
                $u          = $i-1;
            }else{
                fseek($this->fp, $this->getLong3());
                $endIp      = strrev(fread($this->fp, 4));
                if($ip > $endIp){
                    $l      = $i+1;
                }else{
                    $findIp = $this->firstIp + $i*7;
                    break;
                }
            }
        }
        fseek($this->fp, intval($findIp));
        $isPhpVersion71         = !version_compare(phpversion(), '7.1.0', '<');
        $location['startIp']    = long2ip($isPhpVersion71 ? $this->getLong() : strval($this->getLong()));
        $offset                 = $this->getLong3();
        fseek($this->fp, $offset);
        $location['endIp']      = long2ip($isPhpVersion71 ? $this->getLong() : strval($this->getLong()));
        $byte                   = fread($this->fp, 1);
        switch(ord($byte)){
            case 1:{
                $countryOffset  = $this->getLong3();
                fseek($this->fp, $countryOffset);
                $byte           = fread($this->fp, 1);
                switch(ord($byte)){
                    case 2:{
                        fseek($this->fp, $this->getLong3());
                        $location['country']    = $this->getString();
                        fseek($this->fp, $countryOffset + 4);
                        $location['area']       = $this->getArea();
                        break;
                    }
                    default:{
                        $location['country']    = $this->getString($byte);
                        $location['area']       = $this->getArea();
                        break;
                    }
                }
                break;
            }
            case 2:{
                fseek($this->fp, $this->getLong3());
                $location['country']            = $this->getString();
                fseek($this->fp, $offset + 8);
                $location['area']               = $this->getArea();
                break;
            }
            default:{
                $location['country']            = $this->getString($byte);
                $location['area']               = $this->getArea();
                break;
            }
        }
        if(strtoupper($location['country']) === 'CZ88.NET'){
            $location['country']                = 'unknown';
        }else{
            $location['country']                = CommString::strConvert($location['country'], 'UTF-8', 'GBK');
        }
        if(strtoupper($location['area']) === 'CZ88.NET'){
            $location['area']                   = 'unknown';
        }else{
            $location['area']                   = CommString::strConvert($location['area'], 'UTF-8', 'GBK');
        }
        return $location;
    }

    /**
     * @param string $country
     * @return int
     * getCountryNum
     */
    private function getCountryNum(string $country):int
    {
        $country        = trim($country);
        if($country === 'unknown' || mb_strlen($country) < 2) return 0;
        if(isset($this->countryIndexList[$country])) return $this->countryIndexList[$country];
        foreach ($this->countryList as $countryData){
            if(mb_strpos($country, $countryData[1]) !== false){
                return $countryData[0];
            }
        }
        return 0;
    }

    /**
     * @param string $country
     * @param string $area
     * @return array|string[]
     * 分析
     */
    private function analyze(string $country, string $area):array
    {
        $analyzeRes                     = [
            'country'       => '',
            'countryNum'    => 0,
            'province'      => '',
            'provinceCode'  => '',
            'city'          => '',
            'cityCode'      => '',
            'county'        => '',
            'countyCode'    => '',
            'isp'           => '',
        ];
        if($country === 'unknown' || mb_strlen($country) < 2) return $analyzeRes;
        $isChina                        = false;
        $analyzeRes['country']          = $country;
        // 分析省
        $provincePos                    = mb_strpos($country, self::NAME_PROVINCE);
        if($provincePos > 1){
            $isChina                    = true;
            $analyzeRes['province']     = mb_substr($country, 0, $provincePos+1);
            $provinceTmp                = mb_substr($country, $provincePos+1);
            $cityPos                    = mb_strpos($provinceTmp, self::NAME_CITY);
            if($cityPos > 0){
                $analyzeRes['city']     = mb_substr($provinceTmp, 0, $cityPos+1);
                $cityTmp                = mb_substr($provinceTmp, $cityPos+1);
                $countyPos              = mb_strpos($cityTmp, self::NAME_XIAN);
                if($countyPos > 0){
                    $analyzeRes['county'] = mb_substr($cityTmp, 0, $countyPos+1);
                }else{
                    $countyPos          = mb_strpos($cityTmp, self::NAME_QU);
                    if($countyPos > 0) $analyzeRes['county'] = mb_substr($cityTmp, 0, $countyPos+1);
                }
            }
            foreach ($this->provinceList as $provinceData){
                if(mb_strpos($analyzeRes['province'], $provinceData[2]) !== false){
                    $analyzeRes['provinceCode'] = $provinceData[0];
                    break;
                }
            }
        }else{  // 不含省的地区
            foreach ($this->provinceList as $provinceData){
                if(mb_strpos($country, $provinceData[2]) !== false){
                    $isChina                    = true;
                    $analyzeRes['provinceCode'] = $provinceData[0];
                    $analyzeRes['province']     = $provinceData[3];
                    if($provinceData[1] === 1){         // 直辖市
                        $provincePos                    = mb_strpos($country, self::NAME_CITY);
                        if($provincePos > 0){
                            $analyzeRes['city']         = CommString::trimRight($country, self::NAME_CITY);
                            $provinceTmp                = mb_substr($country, $provincePos+1);
                            $cityPos                    = mb_strpos($provinceTmp, self::NAME_QU);
                            if($cityPos > 0) $analyzeRes['city'] = mb_substr($provinceTmp, 0, $cityPos+1);
                        }else{
                            $cityPos                    = mb_strpos($country, self::NAME_QU);
                            if($cityPos > 0) $analyzeRes['city'] = str_replace($provinceData[2], '', mb_substr($country, 0, $cityPos+1));
                        }
                    }else if($provinceData[1] === 2 || $provinceData[1] === 0) {  // 自治区 Or 省
                        $cityPos                    = mb_strpos($country, self::NAME_CITY);
                        if($cityPos > 0){
                            $analyzeRes['city']     = str_replace($provinceData[2], '', mb_substr($country, 0, $cityPos+1));
                            $cityTmp                = mb_substr($country, $cityPos+1);
                            $countyPos              = mb_strpos($cityTmp, self::NAME_XIAN);
                            if($countyPos > 0){
                                $analyzeRes['county']   = mb_substr($cityTmp, 0, $countyPos+1);
                            }else{
                                $countyPos          = mb_strpos($cityTmp, self::NAME_QU);
                                if($countyPos > 0) $analyzeRes['county'] = mb_substr($cityTmp, 0, $countyPos+1);
                            }
                        }
                    }
                    break;
                }
            }
        }
        $isChina && $analyzeRes['country'] = self::NAME_CHINA;
        // 分析ISP
        if($area !== 'unknown' && mb_strlen($area) > 0){
            foreach ($this->ispList as $ispData){
                if(mb_strpos($area, $ispData[0]) !== false){
                    $analyzeRes['isp'] = $ispData[1];
                    break;
                }
            }
        }
        // 国家数字代码
        $analyzeRes['countryNum'] = $this->getCountryNum($analyzeRes['country']);
        return $analyzeRes;
    }
}